#ifndef XENENGIN_XEN_RENDERER_RENDERER3D_HPP
#define XENENGIN_XEN_RENDERER_RENDERER3D_HPP

#include "renderer.hpp"
#include "mesh.hpp"
#include "model.hpp"
#include "texture.hpp"
#include "light.hpp"
#include "cube_map.hpp"
#include "framebuffer.hpp"
#include "xen/config/config.hpp"

namespace Xen {

class Renderer3D {
public:
    static void Init();
    static void Shutdown();

    static Ref<Material> CreateMaterial();
    static Ref<CubeMap> CreateSkyBox(const std::string& top, const std::string& bottom, const std::string& left, const std::string& right, const std::string& front, const std::string& back);

    static void EnableFaceCull();
    static void DisableFaceCull();

    static void EnableDepthTest() { RenderCommand::EnableDepthTest(); }
    static void DisableDepthTest() { RenderCommand::DisableDepthTest(); }
    static bool IsEnabelDepthTest() { return RenderCommand::IsEnabelDepthTest(); }
    static void SetDepthFunc(DepthFunc func) { RenderCommand::SetDepthFunc(func); }

    static void BeginScene(const PerspectiveCamera& camera, const DirectLight& dirlight, const DotLight& dotlight, const SpotLight& spotlight);
    static void EndScene();

    static void SetSkyBox(const Ref<CubeMap>& skybox);
    static Ref<CubeMap> GetSkyBox();

    /*
     * @warn Should be called as the last draw command
     */
    static void DrawSkyBox();

    static void DrawMesh(const Ref<Mesh>& mesh, const glm::vec3& center, const glm::vec3& rotation = {0, 0, 0}, const glm::vec3& scale = {1, 1, 1});
    static void DrawModel(const Ref<Model>& model, const glm::vec3& center, const glm::vec3& rotation = {0, 0, 0}, const glm::vec3& scale = {1, 1, 1});
};

}

#endif
